/******************************************************************************
 * @brief    闪存管理器
 * Change Logs:
 * Date           Author         Email            Notes
 * 2025-01-10     子恒     3393018959@qq.com    初版完成
 ******************************************************************************/
 
#define _B_FLASH_GLOBALS_
#include "b_flash.h"

#if ((B_FLASH_LOG_DEBUG_EN != 0) || (B_FLASH_LOG_INFO_EN != 0))
  const char mode_log[2][10]={"main","back"};
#endif
 
static void dump_hex(const unsigned char *data, size_t length)
{
#if (B_FLASH_LOG_DEBUG_EN != 0)
  for (size_t i = 0; i < length; i++)
  {
    B_FLASH_DEBUG_PRINTF("%02X ", data[i]);
  }
  B_FLASH_DEBUG_PRINTF("\n");
#endif  
}

static uint32_t get_check_sum(uint8_t *pdata, uint32_t size)
{
  uint32_t tmp = 0;
  for(uint32_t i = 0; i < size; i++)
  {
    tmp += pdata[i];
  }
  return tmp;
}

static uint32_t get_address(b_flash_manager_t *flash_manager,index_mode_t mode)
{
  if(mode == INDEX_MAIN)
  {
    return flash_manager->user_init.main_flash_address;
  }
#if(BACK_FUNCTION_EN == 1)   
  if(mode == INDEX_BACK)
  {
    return flash_manager->user_init.back_flash_address;
  }
#endif
  B_FLASH_INFO_PRINTF("[INFO]<b_flash_read_index mode is err>\r\n");
  return 0;
}

static uint32_t b_flash_read_index(b_flash_manager_t *flash_manager,index_mode_t mode)
{
  uint32_t index = 0xffffffff;
  uint32_t address = get_address(flash_manager,mode);

  //遍历标识区，找到第一个不为0的bit
  for(uint16_t i = 0; i < flash_manager->_info.flag_map_number; i++){
    uint32_t tmp;
    flash_manager->user_init.pf_read((address + i * 4),&tmp,4);
    for(uint8_t j = 0; j < 32; j++){
      if(tmp & (0x80000000 >> j)){
        index = i*32+j;
        //如果全部找完都没找到，说明整页被写满了
        if(index >= flash_manager->_info.flag_map_bit_number){
          index = flash_manager->_info.flag_map_bit_number;
        }
        return index;
      }
    }
  } 
  return index;
}

static uint32_t b_flash_add_index(b_flash_manager_t *flash_manager,index_mode_t mode)
{
  //找到当前可写位置
  uint32_t index = b_flash_read_index(flash_manager,mode);
  uint32_t address = get_address(flash_manager,mode);

  uint32_t i = index / 32;
  uint32_t j = ~(0x80000000 >> (index % 32));
  i =  address + i * 4;
  flash_manager->user_init.pf_write(i,&j,4);

  return index;
}
  
static int8_t flash_read_select(b_flash_manager_t *flash_manager, void *read_data, uint32_t size,index_mode_t mode) 
{
  int8_t check_pass = -1;
   
  uint32_t index = b_flash_read_index(flash_manager,mode);
  uint32_t address = get_address(flash_manager,mode);

  address = address + flash_manager->_info.flag_map_number * 4 + (flash_manager->_info.data_word_number * (index - 1))  * 4;

  flash_manager->user_init.pf_read(address,read_data,size);

  B_FLASH_DEBUG_PRINTF("[DEBUG][READ][%s][DATA]<address %08x><inxde %d>\r\n",mode_log[mode],address,index);
  dump_hex(read_data,size);
  
  if(flash_manager->user_init.pf_check != NULL){
    check_pass = flash_manager->user_init.pf_check(read_data,size);  
    if(check_pass != 0){
      B_FLASH_INFO_PRINTF("[INFO][READ][%s]<pf_check err %d>\r\n",mode_log[mode],check_pass);
      return check_pass;
    }
  }
  
  check_pass = -1;
  //读校验地址数据
  uint32_t check_sum;
  uint32_t check_sum_address = address + (flash_manager->_info.data_word_number - 1) * 4;

  flash_manager->user_init.pf_read(check_sum_address,&check_sum,4);
  //对数据和校验地址求校验
  uint32_t check_sum_calc = get_check_sum(read_data,size) + check_sum_address;
  
  if(check_sum == check_sum_calc){
    check_pass = 0;
  }
  
  B_FLASH_DEBUG_PRINTF("[DEBUG][READ][%s][CHECK]<address %08x check %08x calc %08x>\r\n",mode_log[mode],check_sum_address,check_sum,check_sum_calc);
  dump_hex((uint8_t *)(&check_sum),4);
  
  return check_pass;
}

static int8_t flash_write_select(b_flash_manager_t *flash_manager, void *wirte_data, uint32_t size,index_mode_t mode)
{
  int8_t ret = 0;
  uint32_t index   = b_flash_add_index(flash_manager,mode);
  uint32_t address = get_address(flash_manager,mode);

  if(flash_manager->user_init.pf_check != NULL){
    ret = flash_manager->user_init.pf_check(wirte_data,size);  
    if(ret != 0){
      B_FLASH_INFO_PRINTF("[INFO][READ][%s]<pf_check err %d reset default value>\r\n",mode_log[mode],ret);
      if(flash_manager->user_init.pf_default != NULL)flash_manager->user_init.pf_default(wirte_data,size);
    }
  }
  
  if(index >= flash_manager->_info.flag_map_bit_number)
  {
    B_FLASH_INFO_PRINTF("[INFO]<erase address %08x page %d>\r\n",address,flash_manager->user_init.flash_page_numbre);
    ret |= flash_manager->user_init.pf_erase(address, flash_manager->user_init.flash_page_numbre);
    index   = b_flash_add_index(flash_manager,mode);
  }
  
  //从选区找最新地址写
  address = address + flash_manager->_info.flag_map_number * 4 + flash_manager->_info.data_word_number * index  * 4;
  ret |= flash_manager->user_init.pf_write( address , wirte_data, size);

  B_FLASH_DEBUG_PRINTF("[DEBUG][WRIET][%s][DATA]<address %08x><inxde %d>\r\n",mode_log[mode],address,index);
  dump_hex((uint8_t *)(wirte_data),size);
  
  //如果不是第一个位置，就把前面位置的数据打坏
  if(index != 0){
    uint32_t tmp = 0;
    ret |= flash_manager->user_init.pf_write( address - 4 , &tmp, 4);
  }
  
  //写校验数据到选区
  uint32_t check_sum_address = address + (flash_manager->_info.data_word_number - 1) * 4;
  uint32_t check_sum = get_check_sum(wirte_data,size) + check_sum_address;
  ret |= flash_manager->user_init.pf_write( check_sum_address ,(uint8_t *)&check_sum, 4);
  
  B_FLASH_DEBUG_PRINTF("[DEBUG][WRITE][%s][CHECK]<address %08x check %08x>\r\n",mode_log[mode],check_sum_address,check_sum);
  dump_hex((uint8_t *)(&check_sum),4);
  return ret;
}

int8_t b_flash_read(b_flash_manager_t *flash_manager, void *read_data, uint32_t size)
{
  int8_t check_main_pass,check_back_pass;
  
  for(uint8_t i = 0; i < FLASH_READ_MAX_CNT; i++){
    check_main_pass = flash_read_select(flash_manager,read_data,size,INDEX_MAIN);
    if(check_main_pass == 0) break;
  }
#if(BACK_FUNCTION_EN == 1)    
  for(uint8_t i = 0; i < FLASH_READ_MAX_CNT; i++){
    check_back_pass = flash_read_select(flash_manager,read_data,size,INDEX_BACK);
    if(check_back_pass == 0) break;
  }
  //如果两个区都不通过，则复位整个扇区数据,写入默认数据
  if((check_main_pass != 0) && (check_back_pass != 0))
  {
    B_FLASH_INFO_PRINTF("[INFO][error]<Restore the sector to default data.>\r\n");
    flash_manager->user_init.pf_erase(flash_manager->user_init.main_flash_address, flash_manager->user_init.flash_page_numbre);
    flash_manager->user_init.pf_erase(flash_manager->user_init.back_flash_address, flash_manager->user_init.flash_page_numbre);
    if(flash_manager->user_init.pf_default != NULL)flash_manager->user_init.pf_default(read_data,size);
    b_flash_write(flash_manager,read_data,size);
    return 1;
  }
  
  //如果主区不通过，备份区通过，擦除主区，重写标识，把备份区数据写入
  if((check_main_pass != 0) && (check_back_pass == 0))
  {
    B_FLASH_INFO_PRINTF("[INFO][error]<main flash Data is incorrect, rewrite the flash.>\r\n");
    flash_manager->user_init.pf_erase(flash_manager->user_init.main_flash_address, flash_manager->user_init.flash_page_numbre);
    flash_read_select(flash_manager,read_data,size,INDEX_BACK);
    flash_write_select(flash_manager,read_data,size,INDEX_MAIN);
    return 1;
  }
  
  //如果主区通过，备份区不通过，擦除备份区，重写标识，读主区数据写入
  if((check_back_pass != 0) && (check_main_pass == 0))
  {
    B_FLASH_INFO_PRINTF("[INFO][error]<back flash Data is incorrect, rewrite the flash.>\r\n");
    flash_manager->user_init.pf_erase(flash_manager->user_init.back_flash_address, flash_manager->user_init.flash_page_numbre);
    flash_read_select(flash_manager,read_data,size,INDEX_MAIN);
    flash_write_select(flash_manager,read_data,size,INDEX_BACK);
    return 1;
  }
#endif  
  return check_main_pass;
}

int8_t b_flash_create(b_flash_manager_t *flash_manager, void *wirte_data, uint32_t size)
{
  if(flash_manager->user_init.pf_write == NULL){
    B_FLASH_INFO_PRINTF("[INFO][ERROR]<pf_write is null>");
    return 1;
  }
  
  if(flash_manager->user_init.pf_read == NULL){
    B_FLASH_INFO_PRINTF("[INFO][ERROR]<pf_read is null>");
    return 1;
  }
  
  if(flash_manager->user_init.pf_erase == NULL){
    B_FLASH_INFO_PRINTF("[INFO][ERROR]<pf_erase is null>");
    return 1;
  }
  
  if(flash_manager->user_init.pf_default == NULL){
    B_FLASH_INFO_PRINTF("[INFO][WARNING]<pf_default is null>");
    return 1;
  }
  
  if(flash_manager->user_init.pf_check == NULL){
    B_FLASH_INFO_PRINTF("[INFO][WARNING]<pf_check is null>");
    return 1;
  }
  
  if(flash_manager->user_init.main_flash_address & 0x03){
    B_FLASH_INFO_PRINTF("[INFO][WARNING]<main_flash_address no 4-byte aligned>");
    return 1;
  }
#if(BACK_FUNCTION_EN == 1)    
  if(flash_manager->user_init.back_flash_address & 0x03){
    B_FLASH_INFO_PRINTF("[INFO][WARNING]<back_flash_address no 4-byte aligned>");
    return 1;
  }
#endif  
  //数据块字数，多占一个字用来存校验数据
  flash_manager->_info.data_word_number =  (size+3)/4 + 1;
  flash_manager->_info.flag_map_number  =  (flash_manager->user_init.flash_page_size * flash_manager->user_init.flash_page_numbre)/128;
  flash_manager->_info.flag_map_bit_number = ((flash_manager->user_init.flash_page_size * flash_manager->user_init.flash_page_numbre)/4 - flash_manager->_info.flag_map_number)/flash_manager->_info.data_word_number;

  B_FLASH_INFO_PRINTF("[INFO][INIT]<data_word = %d, flag_map_number = %d flag_map_bit_number = %d>\r\n",flash_manager->_info.data_word_number,flash_manager->_info.flag_map_number,flash_manager->_info.flag_map_bit_number);
  
  //写标识区
  uint32_t index = 0x7fffffff;
  flash_manager->user_init.pf_write(flash_manager->user_init.main_flash_address ,(uint8_t *)(&index), 4);
  
#if(BACK_FUNCTION_EN == 1)      
  flash_manager->user_init.pf_write(flash_manager->user_init.back_flash_address ,(uint8_t *)(&index), 4);
#endif  
  
  b_flash_read(flash_manager,wirte_data,size);
  return 0;
}

int8_t b_flash_write(b_flash_manager_t *flash_manager, void *wirte_data, uint32_t size)
{
  uint8_t ret = 0;
  ret |= flash_write_select(flash_manager,wirte_data,size,INDEX_MAIN);
#if(BACK_FUNCTION_EN == 1)  
  ret |= flash_write_select(flash_manager,wirte_data,size,INDEX_BACK);
#endif  
  return ret;
}



